/*
 *  src/process_control/writer_reader.c
 *
 *  Harry Wei <harryxiyou@gmail.com> (C) 2011
 */
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>

#include "semun.h"
#include "pv.h"

#define SHM_SIZE 100

static char *shm = NULL;
static int shmid = 0;
static int semid = 0;

static void waitsem(int semid, int index)
{
	while (0 == semctl(semid, index, GETVAL, 0)) {
		sleep(1);
		g_message("%s -- I am waiting ...\n", __func__);
	}
	return ;
}

static void my_wsleep(int i)
{
	while (i--) {
		g_message("%s -- writer is sleeping ...\n", __func__);
		sleep(1);
	}
	return ;
}

static void my_rsleep(int i)
{
	while (i--) {
		g_message("%s -- reader is sleeping ...\n", __func__);
		sleep(1);
	}
	return ;
}

#if 0
static void handler(int sig)
{
	g_message("%s -- free resource!\n", __func__);
	if (-1 == shmdt(shm)) {
		g_message("%s -- shmdt error!\n", __func__);
		return ;
	}
	if (-1 == shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0)) {
		g_message("%s -- shmctl error!\n", __func__);
		return ;
	}
	if (-1 == semctl(semid, 0, IPC_RMID)) {
		g_message("%s -- semctl error!\n", __func__);
		return ;
	}
}
#endif

int reader_writer(void)
{
	pid_t pid;
	key_t key;
	int i = 0;
	int j = 0;
	int proj_id = 0;
	union semun arg;

	if (-1 == (key = ftok(".", proj_id))) {
		g_message("%s -- get key value error!\n", __func__);
		return -1;
	}
	if (-1 == (semid = semget(key, 1, IPC_CREAT | 0666))) {
		g_message("%s -- semget error!\n", __func__);
		return -1;
	}
	arg.val = 1;
	if (-1 == semctl(semid, 0, SETVAL, arg)) {
		g_message("%s -- semctl error!\n", __func__);
		return -1;
	}
	if (-1 == (shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666))) {
		g_message("%s -- shmget error!\n", __func__);
		return -1;
	}
	if ((shm = (char *) shmat(shmid, 0, 0)) == (char *) -1) {
		g_message("%s -- shmat error!\n", __func__);
		return -1;
	}
	pid = fork();
	switch (pid) {
		case -1:
			g_message("%s -- fork error!\n", __func__);
			return -1;
		case 0:
			while (1)
			{
//				signal(SIGINT, handler);
				waitsem(semid, 0);
				p(semid, 0);
				g_print("writer...\n");
				char *s = shm;
				char c = 0;
				for (c = 'A'; c <= 'Z'; c++) {
					*s = c;
					s += 1;
				}
				s = NULL;
				my_rsleep(5);
				v(semid, 0);
				my_wsleep(3);
			}
		default:
			while (1)
			{
//				signal(SIGINT, handler);
				waitsem(semid, 0);
				p(semid, 0);
				g_print("reader...\n");
				g_print("%s\n", shm);
				my_wsleep(5);
				v(semid, 0);
				my_rsleep(3);
			}
	}
	return 0;
}
